package fr.licpro.filebox.activity.fragments;

import java.util.ArrayList;
import java.util.List;

import android.app.ListFragment;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import fr.licpro.filebox.R;
import fr.licpro.filebox.activity.ListActivity;
import fr.licpro.filebox.adapters.ListItemAdapter;
import fr.licpro.filebox.database.BusinessLayer;
import fr.licpro.filebox.model.Content;
import fr.licpro.filebox.model.File;
import fr.licpro.filebox.service.SyncService;
import fr.licpro.filebox.service.sync.FilesSync;
import fr.licpro.filebox.utils.FileCache;

/**
 * Fragment which shows the file list
 * @author Abdessamad EL FATTAKE
 * @author Sylvain LE GOUELLEC
 */
public class FileboxListFragment extends ListFragment {
	
	/**
	 * Brodcast Receiver
	 */
	private SyncReceiver mReceiver;
	
	/**
	 * Layout with loading indicator
	 */
	private RelativeLayout mLoad;
	
	/**
	 * Array of files get from BDD or Service
	 */
	private ArrayList<File> mFiles;
	
	/**
	 *	Adapter for display a list of File
	 */
	private ListItemAdapter mAdapter;
	
	/**
	 * Boolean to know if the fragment is saved in BackStack
	 */
	private boolean mFromBackStack = false;
	
	/**
	 * Permit to know if fragment is on back stack
	 * @return True if yes
	 */
	public boolean isOnBackStack()
	{
		return mFromBackStack;
	}
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		return inflater.inflate(R.layout.fragment_list, container,false);
	}
	
	@Override
	public void onSaveInstanceState(Bundle outState) {
		outState.putParcelableArrayList("FILES", mFiles);
		outState.putBoolean("BACK", mFromBackStack);
		super.onSaveInstanceState(outState);
	}
	
	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		
		mLoad = (RelativeLayout) getView().findViewById(R.id.load_detail_waiting);
		
		if(savedInstanceState != null && savedInstanceState.containsKey("BACK"))
		{
			mFromBackStack = savedInstanceState.getBoolean("BACK");
		}
		
		if(!mFromBackStack)
		{
			mFiles = new ArrayList<File>();
		}
		
		mAdapter = new ListItemAdapter(getActivity(), R.layout.list_view_item, mFiles);
		setListAdapter(mAdapter);
		
		// If the activity exit the Pause state
		// we restore files' tree
		if(savedInstanceState != null && savedInstanceState.containsKey("FILES") && !mFromBackStack)
		{
			ArrayList<File> savedFiles = savedInstanceState.getParcelableArrayList("FILES");
			mFiles.addAll(savedFiles);
			mAdapter.notifyDataSetChanged();
			mLoad.setVisibility(View.GONE);
		}
		// Otherwise we launch the service which will get ROOT files
		// or get them directly in the database
		else if(!mFromBackStack)
		{
			// If a Network access is available
			// we call the service
			if(SyncService.isNetworkAvailable(getActivity()))
			{
				FilesSync filesync = new FilesSync("0", "ROOT", null, getActivity());
				
				Intent service = new Intent(FileboxListFragment.this.getActivity(), SyncService.class);
				service.putExtra(SyncService.SYNC_CLASS_INTENT, filesync);
				
				FileboxListFragment.this.getActivity().startService(service);
			}
			// Otherwise we get the database data
			else
			{
				List<File> listFiles = BusinessLayer.getRootFolder(getActivity(), File.class);
				
				// Update the view
				updateAdapter(listFiles);
				mLoad.setVisibility(View.GONE);
			}
		}
		mFromBackStack = false;
		mLoad.setVisibility(View.GONE);
	}
	
	@Override
	public void onListItemClick(ListView l, View v, int position, long id) {
		
		File selectedFile = (File) getListView().getItemAtPosition(position);
		
		// If a network access is available
		// we call the service
		if(SyncService.isNetworkAvailable(getActivity()))
		{
			if(selectedFile.getName().equals(".."))
				goToParent();
			else
			{
				FileCache cache = new FileCache(getActivity());
				java.io.File file = cache.getFile(selectedFile.getHashId());
				

				if(selectedFile.getFileType() != null && file != null)
				{
					Content contentFileCache = new Content(selectedFile.getHashId(), selectedFile.getFileType().getMimeType());
					((ListActivity)getActivity()).showDetailsFragment(FileboxListFragment.this, contentFileCache);
				}
				else
				{
					mLoad.setVisibility(View.VISIBLE);
					
					Intent service = new Intent(FileboxListFragment.this.getActivity(), SyncService.class);
	
					FilesSync filesync = new FilesSync(
							String.format("%d", selectedFile.getLastModification().getTime()),
							selectedFile.getHashId(),
							selectedFile);
	
					service.putExtra(SyncService.SYNC_CLASS_INTENT, filesync);
	
					FileboxListFragment.this.getActivity().startService(service);
				}
			}
		}
		// Otherwise we get directly the database files
		else
		{
			if(selectedFile.getFileType() == null)
			{
				List<File> listFiles = BusinessLayer.getFilesChild(getActivity(), File.class, selectedFile.getHashId());
				
				if(!selectedFile.getHashId().equals("ROOT"))
				{
					selectedFile.getParentFolder().setName("..");
					listFiles.add(0, selectedFile.getParentFolder());
				}
				
				// Update the view
				updateAdapter(listFiles);
			}
			// If selectedFile is a file and user is not connected
			else 
			{
				FileCache cache = new FileCache(getActivity());
				java.io.File file = cache.getFile(selectedFile.getHashId());
				// If file is null, so file is not in cache. An error message is displaying.
				if(file == null)
					Toast.makeText(getActivity(), R.string.not_connected, Toast.LENGTH_SHORT).show();
				else{
					Content contentFileCache = new Content(selectedFile.getHashId(), selectedFile.getFileType().getMimeType());
					((ListActivity)getActivity()).showDetailsFragment(FileboxListFragment.this, contentFileCache);
				}
			}
		}
		
		super.onListItemClick(l, v, position, id);
	}
	
	/**
	 * Saved constant to service
	 */
	@Override
	public void onStart(){
		mReceiver = new SyncReceiver();
		getActivity().registerReceiver(mReceiver, new IntentFilter(FilesSync.FILES_INFO));
		getActivity().registerReceiver(mReceiver, new IntentFilter(FilesSync.FILE_CONTENT));
		getActivity().registerReceiver(mReceiver, new IntentFilter(FilesSync.ERROR_CONNECTION));
		super.onStart();
	}
	
	@Override
	public void onStop() {
		if(mReceiver != null)
			getActivity().unregisterReceiver(mReceiver);
		super.onStop();
	}
	
	@Override
	public void onDestroyView() {
		mFromBackStack = true;
		super.onDestroyView();
	}
	
	/**
	 * Update the adapter of list view and refresh view
	 * @param list	List of file to display
	 */	
	private void updateAdapter(List<File> list) 
	{
		mFiles.clear();
		mFiles.addAll(list);
		
		mAdapter.notifyDataSetChanged();
	}
	
	/**
	 * Return to parent file. Return a boolean if we are in root folder and user wants to go back.
	 * So if it's case, application is closed.
	 * @author Sylvain Le Gouellec
	 * @since 1.0.0
	 * @return	Return a boolean to know if go back is possible
	 */
	public boolean goToParent()
	{
		File parentFile = mFiles.get(0);
		
		if(!mFiles.get(0).getName().equals(".."))
			return false;
		
		List<File> listFiles = BusinessLayer.getFilesChild(getActivity(), File.class, parentFile.getHashId());

		if(!parentFile.getHashId().equals("ROOT"))
		{
			parentFile.getParentFolder().setName("..");
			listFiles.add(0, parentFile.getParentFolder());
		}
		// Update the view
		updateAdapter(listFiles);
		
		return true;
	}
	
	/*********************************************************/
	/******** INNER CLASS FOR THE BROADCAST RECEIVER *********/
	/*********************************************************/
	private class SyncReceiver extends BroadcastReceiver
	{
		/* (non-Javadoc)
		 * @see android.content.BroadcastReceiver#onReceive(android.content.Context, android.content.Intent)
		 */
		@Override
		public void onReceive(Context context, Intent intent) 
		{		
			// Files are returned by the service
			if(intent.getAction().equals(FilesSync.FILES_INFO))
			{
				ArrayList<File> listFiles = intent.getParcelableArrayListExtra(FilesSync.FILES_INFO);
			
				updateAdapter(listFiles);
				mLoad.setVisibility(View.GONE);
			}
			else if(intent.getAction().equals(FilesSync.FILE_CONTENT))
			{
				Content content = intent.getParcelableExtra(FilesSync.FILE_CONTENT);
				
				((ListActivity)getActivity()).showDetailsFragment(FileboxListFragment.this,content);
			}
			// An error is happened
			else if(intent.getAction().equals(FilesSync.ERROR_CONNECTION))
			{
				String message = (String)intent.getStringExtra(FilesSync.ERROR_CONNECTION);	
				Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
				mLoad.setVisibility(View.GONE);
			}
		}
	}
	
	/*********************************************************/
	/******** END OF INNER CLASS FOR THE BROADCAST RECEIVER *****/
	/*********************************************************/
	
	/**
	 * Get the list of files
	 * @return List of files
	 */
	public ArrayList<File> getFiles() {
		return mFiles;
	}

	/**
	 * Restore the list of files (useful when fragment is on back stack)
	 * @param restore_files Files to restore
	 */
	public void restoreFiles(ArrayList<File> restore_files) {
		mFiles = new ArrayList<File>(restore_files);
	}

	/**
	 * Change a boolean to know later if fragment is on back stack
	 * @param b True if yes
	 */
	public void setOnBackStack(boolean b) {
		mFromBackStack = b;
	}
	
	/**
	 * Hides the load layout
	 * @param state Not used
	 */
	public void disableLoadLayout(boolean state)
	{
		mLoad.setVisibility(View.GONE);
	}
}
